package com.tianhai.db.index;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Random;

import com.tianhai.db.DiskManager;

/**
 * B+树索引测试类
 */
public class BPlusTreeTest {
    
    public static void main(String[] args) {
        System.out.println("========================================");
        System.out.println("    B+树索引测试");
        System.out.println("========================================\n");
        
        DiskManager diskManager = null;
        String dbFilePath = "bplustree_test.db";
        
        try {
            // 清理旧测试文件
            File oldFile = new File(dbFilePath);
            if (oldFile.exists()) {
                oldFile.delete();
                System.out.println("✓ 已清理旧测试文件\n");
            }
            
            // 创建DiskManager和B+树
            System.out.println("【初始化】");
            diskManager = new DiskManager(dbFilePath);
            int order = 64; // B+树的阶数
            BPlusTree bTree = new BPlusTree(diskManager, order);
            System.out.println("✓ B+树创建成功");
            System.out.println("  - 阶数: " + order);
            System.out.println("  - 根节点页ID: " + bTree.getRootPageId());
            System.out.println();
            
            int totalTests = 0;
            int passedTests = 0;
            
            // 测试1: 插入单个键值对
            System.out.println("【测试1】插入单个键值对");
            try {
                bTree.insert(100, 1001);
                System.out.println("✓ 插入成功: (100, 1001)");
                passedTests++;
            } catch (Exception e) {
                System.out.println("✗ 插入失败: " + e.getMessage());
            }
            totalTests++;
            System.out.println();
            
            // 测试2: 搜索已存在的键
            System.out.println("【测试2】搜索已存在的键");
            try {
                Integer result = bTree.search(100);
                if (result != null && result == 1001) {
                    System.out.println("✓ 搜索成功: key=100, value=" + result);
                    passedTests++;
                } else {
                    System.out.println("✗ 搜索失败: 值不匹配");
                }
            } catch (Exception e) {
                System.out.println("✗ 搜索失败: " + e.getMessage());
            }
            totalTests++;
            System.out.println();
            
            // 测试3: 搜索不存在的键
            System.out.println("【测试3】搜索不存在的键");
            try {
                Integer result = bTree.search(999);
                if (result == null) {
                    System.out.println("✓ 搜索成功: key=999 不存在");
                    passedTests++;
                } else {
                    System.out.println("✗ 搜索失败: 应该返回null");
                }
            } catch (Exception e) {
                System.out.println("✗ 搜索失败: " + e.getMessage());
            }
            totalTests++;
            System.out.println();
            
            // 测试4: 批量插入（有序）
            System.out.println("【测试4】批量插入有序数据");
            try {
                int insertCount = 1000;
                System.out.println("正在插入 " + insertCount + " 条有序数据...");
                
                long startTime = System.currentTimeMillis();
                for (int i = 1; i <= insertCount; i++) {
                    bTree.insert(i, i * 10);
                    
                    if (i % 100 == 0) {
                        System.out.print("  进度: " + i + "/" + insertCount + "\r");
                    }
                }
                long endTime = System.currentTimeMillis();
                
                System.out.println("\n✓ 批量插入成功");
                System.out.println("  - 插入数量: " + insertCount);
                System.out.println("  - 耗时: " + (endTime - startTime) + " ms");
                System.out.println("  - 平均: " + String.format("%.4f", (endTime - startTime) / (double) insertCount) + " ms/条");
                passedTests++;
            } catch (Exception e) {
                System.out.println("✗ 批量插入失败: " + e.getMessage());
                e.printStackTrace();
            }
            totalTests++;
            System.out.println();
            
            // 测试5: 验证批量插入的数据
            System.out.println("【测试5】验证批量插入的数据");
            try {
                boolean allCorrect = true;
                int sampleSize = 100;
                Random random = new Random(12345);
                
                System.out.println("随机抽样验证 " + sampleSize + " 条数据...");
                for (int i = 0; i < sampleSize; i++) {
                    int key = random.nextInt(1000) + 1;
                    Integer value = bTree.search(key);
                    
                    if (value == null || value != key * 10) {
                        System.out.println("✗ 数据不一致: key=" + key + ", expected=" + (key * 10) + ", actual=" + value);
                        allCorrect = false;
                        break;
                    }
                }
                
                if (allCorrect) {
                    System.out.println("✓ 数据验证通过");
                    passedTests++;
                } else {
                    System.out.println("✗ 数据验证失败");
                }
            } catch (Exception e) {
                System.out.println("✗ 数据验证失败: " + e.getMessage());
            }
            totalTests++;
            System.out.println();
            
            // 测试6: 范围搜索
            System.out.println("【测试6】范围搜索");
            try {
                int startKey = 50;
                int endKey = 100;
                
                List<BPlusTree.KeyValuePair> results = bTree.rangeSearch(startKey, endKey);
                
                boolean rangeCorrect = true;
                if (results.size() != (endKey - startKey + 1)) {
                    System.out.println("✗ 范围搜索结果数量不匹配");
                    rangeCorrect = false;
                } else {
                    // 验证结果的正确性
                    for (int i = 0; i < results.size(); i++) {
                        BPlusTree.KeyValuePair pair = results.get(i);
                        int expectedKey = startKey + i;
                        int expectedValue = expectedKey * 10;
                        
                        if (pair.key != expectedKey || pair.value != expectedValue) {
                            System.out.println("✗ 范围搜索结果不正确: " + pair);
                            rangeCorrect = false;
                            break;
                        }
                    }
                }
                
                if (rangeCorrect) {
                    System.out.println("✓ 范围搜索成功");
                    System.out.println("  - 范围: [" + startKey + ", " + endKey + "]");
                    System.out.println("  - 结果数量: " + results.size());
                    System.out.println("  - 前5个结果: " + results.subList(0, Math.min(5, results.size())));
                    passedTests++;
                } else {
                    System.out.println("✗ 范围搜索失败");
                }
            } catch (Exception e) {
                System.out.println("✗ 范围搜索失败: " + e.getMessage());
                e.printStackTrace();
            }
            totalTests++;
            System.out.println();
            
            // 测试7: 批量插入（随机）
            System.out.println("【测试7】批量插入随机数据");
            try {
                int insertCount = 500;
                Random random = new Random(54321);
                
                System.out.println("正在插入 " + insertCount + " 条随机数据...");
                
                long startTime = System.currentTimeMillis();
                for (int i = 0; i < insertCount; i++) {
                    int key = random.nextInt(10000) + 2000; // 2000-12000
                    int value = key + 5000;
                    bTree.insert(key, value);
                    
                    if ((i + 1) % 100 == 0) {
                        System.out.print("  进度: " + (i + 1) + "/" + insertCount + "\r");
                    }
                }
                long endTime = System.currentTimeMillis();
                
                System.out.println("\n✓ 随机数据插入成功");
                System.out.println("  - 插入数量: " + insertCount);
                System.out.println("  - 耗时: " + (endTime - startTime) + " ms");
                passedTests++;
            } catch (Exception e) {
                System.out.println("✗ 随机数据插入失败: " + e.getMessage());
                e.printStackTrace();
            }
            totalTests++;
            System.out.println();
            
            // 测试8: 大范围搜索
            System.out.println("【测试8】大范围搜索");
            try {
                int startKey = 1;
                int endKey = 500;
                
                long startTime = System.currentTimeMillis();
                List<BPlusTree.KeyValuePair> results = bTree.rangeSearch(startKey, endKey);
                long endTime = System.currentTimeMillis();
                
                System.out.println("✓ 大范围搜索成功");
                System.out.println("  - 范围: [" + startKey + ", " + endKey + "]");
                System.out.println("  - 结果数量: " + results.size());
                System.out.println("  - 耗时: " + (endTime - startTime) + " ms");
                passedTests++;
            } catch (Exception e) {
                System.out.println("✗ 大范围搜索失败: " + e.getMessage());
            }
            totalTests++;
            System.out.println();
            
            // 测试9: 持久化测试（关闭并重新打开）
            System.out.println("【测试9】持久化测试");
            try {
                // 关闭DiskManager
                diskManager.close();
                System.out.println("  - 已关闭数据库");
                
                // 重新打开
                diskManager = new DiskManager(dbFilePath);
                BPlusTree newBTree = new BPlusTree(diskManager, order);
                System.out.println("  - 已重新打开数据库");
                
                // 验证数据是否还在
                Integer value = newBTree.search(100);
                if (value != null && value == 1001) {
                    System.out.println("✓ 持久化测试通过");
                    System.out.println("  - 验证数据: key=100, value=" + value);
                    passedTests++;
                } else {
                    System.out.println("✗ 持久化测试失败: 数据丢失");
                }
            } catch (Exception e) {
                System.out.println("✗ 持久化测试失败: " + e.getMessage());
            }
            totalTests++;
            System.out.println();
            
            // 测试总结
            System.out.println("========================================");
            System.out.println("           测试结果汇总");
            System.out.println("========================================");
            System.out.println("总测试数: " + totalTests);
            System.out.println("通过数: " + passedTests);
            System.out.println("失败数: " + (totalTests - passedTests));
            System.out.println("通过率: " + (passedTests * 100 / totalTests) + "%");
            System.out.println("----------------------------------------");
            
            if (passedTests == totalTests) {
                System.out.println("✓✓✓ 所有测试通过！");
            } else {
                System.out.println("✗✗✗ 部分测试失败");
            }
            System.out.println("========================================");
            
        } catch (Exception e) {
            System.err.println("✗ 测试过程中发生异常: " + e.getMessage());
            e.printStackTrace();
        } finally {
            if (diskManager != null && !diskManager.isClosed()) {
                try {
                    diskManager.close();
                    System.out.println("\n✓ DiskManager已关闭");
                } catch (IOException e) {
                    System.err.println("✗ 关闭DiskManager时发生异常: " + e.getMessage());
                }
            }
        }
    }
}
